﻿//========================================================================//
//      Copyright 2011, Smilodon Studio Inc.
//      All rights reserved.
//========================================================================//

/**
 *	model
 *	@author: CYS
 */
var model = function( mfile, texfile )
{
	this.pos = new vec3(0, 0, 0);
	this.dir = new vec3(0,0,-1);
	this.v = new vec3();
	this.a = new vec3();
	this.pitch = 0;
	this.oldPitch = 0;

	this.offsets = [];
	this.indexBuffer = null;
	this.posBuffer = null;
	this.norBuffer = null;
	this.uvBuffer  = null;
	this.effect = null;
	this.uvEnable = false;
	this.norEnable = false;
	this.loaded = false;
	this.center = new vec3(0, 0, 0);
	this.r = 0;

	//this.initBuffers(mfile);
	this.initCTM(mfile);
	this.initShader();
	this.texDiffuse = image.load2D(texfile, [0, 200, 250, 255]);


};


model.prototype.initCTM = function(mfile)
{
	var scope = this;
	var posBuffer = this.posBuffer = gl.createBuffer();
	var norBuffer = this.norBuffer = gl.createBuffer();
	var uvBuffer = this.uvBuffer = gl.createBuffer();
	var indexBuffer = this.indexBuffer = gl.createBuffer();

	var request = new XMLHttpRequest();
	request.open("GET", mfile, true);
  	request.overrideMimeType("text/plain; charset=x-user-defined");

	request.onreadystatechange = function ()
	{
		if (request.readyState == 3 || request.readyState == 4)
		{
			var downloading = "Downloading... "
			+ formatNumber(request.responseText.length / 1048576, 2) + " MB";
		}

		if (request.readyState == 4 && (request.status == 200 || request.status == 0) )
		{
			var file = new CTM.File( new CTM.Stream(request.responseText) );

			//scope.initOffsets(scope.offsets, file);
			scope.offsets.push( {start: 0, count: file.body.indices.length, index: 0} );

			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(file.body.indices), gl.STATIC_DRAW);
			indexBuffer.itemSize = 1;
			indexBuffer.numItems = file.body.indices.length;

			var v = file.body.vertices;
			gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(v), gl.STATIC_DRAW);
			posBuffer.itemSize = 3;
			posBuffer.numItems = v.length/3;

			for(var i = 0; i < v.length; i++)
			{
				scope.center.e[0] += v[i];
				scope.center.e[1] += v[++i];
				scope.center.e[2] += v[++i];
			}
			scope.center.div(v.length/3);

			for(var i = 0; i < v.length; i++)
			{
				var p = new vec3(v[i], v[++i], v[++i]);
				var rr = (p.sub(scope.center)).length();
				if(scope.r < rr) scope.r = rr;
			}

			if(file.body.normals)
			{
				gl.bindBuffer(gl.ARRAY_BUFFER, norBuffer);
				gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(file.body.normals), gl.STATIC_DRAW);
				norBuffer.itemSize = 3;
				norBuffer.numItems = file.body.normals.length/3;
			}

			if(file.body.uvMaps)
			{
				gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
				gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(file.body.uvMaps[0].uv), gl.STATIC_DRAW);
				uvBuffer.itemSize = 2;
				uvBuffer.numItems = file.body.uvMaps[0].uv.length/2;
				scope.uvEnable = true;
			}

			if(file.body.attMaps)
			{
				vertexColorBuffer = gl.createBuffer();
				gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
				gl.bufferData(gl.ARRAY_BUFFER, file.body.attrMaps[0].attr, gl.STATIC_DRAW);
				vertexColorBuffer.itemSize = 4;
				vertexColorBuffer.numItems = file.body.attrMaps[0].attr.length/4;
			}

			scope.loaded = true;
		}
	}


	request.send();

}

model.prototype.initOffsets = function(offsets, file)
{
	alert("offset!");
	var indices = file.body.indices;
	var start = 0;
	var min = file.body.vertices.length;
	var max = 0;
	var minPrev = min;

	for (var i = 0; i < indices.length;)
	{

		for (var j = 0; j < 3; ++j)
		{
			var idx = indices[i++];

			if (idx < min) min = idx;
			if (idx > max) max = idx;
		}

		if (max - min > 65535)
		{
			i -= 3;

			for (var k = start; k < i; ++ k)
			{
				indices[k] -= minPrev;
			}
			offsets.push( {start: start, count: i - start, index: minPrev} );

			start = i;
			min = file.body.vertices.length;
			max = 0;
		}

		minPrev = min;
	}

	for (var k = start; k < i; ++ k)
	{
		indices[k] -= minPrev;
	}

	offsets.push( {start: start, count: i - start, index: minPrev} );
}



model.prototype.initBuffers = function(file)
{
	var scope = this;
	var posBuffer = this.posBuffer = gl.createBuffer();
	var norBuffer = this.norBuffer = gl.createBuffer();
	var uvBuffer = this.uvBuffer = gl.createBuffer();
	var indexBuffer = this.indexBuffer = gl.createBuffer();
	var request = new XMLHttpRequest();
	request.open("GET", file);
	request.onreadystatechange = function ()
	{
		if (request.readyState == 4)
		{
			var data = JSON.parse(request.responseText);

			gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.pos), gl.STATIC_DRAW);
			posBuffer.itemSize = 3;
			posBuffer.numItems = data.pos.length/3;

			for(var i = 0; i < data.pos.length; i++)
			{
				scope.center.e[0] += data.pos[i];
				scope.center.e[1] += data.pos[++i];
				scope.center.e[2] += data.pos[++i];
			}
			scope.center.div(data.pos.length/3);

			for(var i = 0; i < data.pos.length; i++)
			{
				var p = new vec3(data.pos[i],data.pos[++i],data.pos[++i]);
				var rr = (p.sub(scope.center)).length();
				if(scope.r < rr) scope.r = rr;
			}

			gl.bindBuffer(gl.ARRAY_BUFFER, norBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.nor), gl.STATIC_DRAW);
			norBuffer.itemSize = 3;
			norBuffer.numItems = data.nor.length/3;

			gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.texcoord), gl.STATIC_DRAW);
			uvBuffer.itemSize = 2;
			uvBuffer.numItems = data.texcoord.length/2;

			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(data.indices), gl.STATIC_DRAW);
			indexBuffer.itemSize = 1;
			indexBuffer.numItems = data.indices.length;
			scope.loaded = true;
		}
	}


	request.send();

}


model.prototype.isLoaded = function()
{
	return this.loaded && this.texDiffuse.loaded;
}


model.prototype.initShader = function()
{
	this.effect = new program();
	this.effect.loadFromID("vsModel");
	this.effect.loadFromID("psModel");
	this.effect.link();

	this.effect.apply();
	this.effect.pos = gl.getAttribLocation(this.effect.program, "aPos");
	this.effect.nor = gl.getAttribLocation(this.effect.program, "aNor");
	this.effect.tc = gl.getAttribLocation(this.effect.program, "aTc");

	this.effect.time = gl.getUniformLocation( this.effect.program, 'time' );
	this.effect.resolution = gl.getUniformLocation( this.effect.program, 'resolution' );
	this.effect.mouse = gl.getUniformLocation( this.effect.program, 'mouse' );
	this.effect.matMVP = gl.getUniformLocation( this.effect.program, 'matMVP' );
	this.effect.sampler = gl.getUniformLocation(this.effect.program, 'sampler');

}



model.prototype.set = function()
{
	this.effect.apply();

	gl.uniform1f( this.effect.time, timer.time/1000 );
	gl.uniform2f( this.effect.resolution, canvas.width, canvas.height );
	gl.uniform2f( this.effect.mouse, mouse.x, mouse.y);

	gl.activeTexture(gl.TEXTURE0);
	gl.bindTexture(gl.TEXTURE_2D, this.texDiffuse);
	gl.uniform1i(this.effect.sampler, 0);

}


model.prototype.setMVP = function(mvp)
{
	gl.uniformMatrix4fv(this.effect.matMVP, false, mvp.e);
}


model.prototype.draw = function()
{
	for (var i = 0; i < this.offsets.length; ++ i)
	{
		gl.enableVertexAttribArray(this.effect.pos);
		gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer);
		gl.vertexAttribPointer(this.effect.pos, this.posBuffer.itemSize, gl.FLOAT, false, 0, this.offsets[i].index * 4 * 3);

		gl.enableVertexAttribArray(this.effect.nor);
		gl.bindBuffer(gl.ARRAY_BUFFER, this.norBuffer);
		gl.vertexAttribPointer(this.effect.nor, this.norBuffer.itemSize, gl.FLOAT, false, 0, this.offsets[i].index * 4 * 3);

		//if(vertexColorBuffer)
		//{
		//	gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
		//	gl.vertexAttribPointer(shaderProgram.vertexColorAttribute,
		//	vertexColorBuffer.itemSize, gl.FLOAT, false, 0, offsets[i].index * 4 * 4);
		//}

		if(this.uvEnable)
		{
			gl.enableVertexAttribArray(this.effect.tc);
			gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
			gl.vertexAttribPointer(this.effect.tc, this.uvBuffer.itemSize, gl.FLOAT, false, 0, this.offsets[i].index * 4 * 2 );
		}

		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
		gl.drawElements(gl.TRIANGLES, this.offsets[i].count, gl.UNSIGNED_SHORT, this.offsets[i].start * 2);


	}


}
